package com.jichangxiu.server.platform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jichangxiu.common.annotation.DataScope;
import com.jichangxiu.common.constant.Constant;
import com.jichangxiu.common.entity.bo.PageData;
import com.jichangxiu.common.exception.ServiceException;
import com.jichangxiu.common.utils.StrUtils;
import com.jichangxiu.common.utils.TokenUtils;
import com.jichangxiu.framework.mybatis.BaseServiceImpl;
import com.jichangxiu.server.platform.entity.dto.PlatformRoleQueryDto;
import com.jichangxiu.server.platform.entity.map.PlatformDeptRoleBasic;
import com.jichangxiu.server.platform.entity.map.PlatformRoleBasic;
import com.jichangxiu.server.platform.entity.map.PlatformRoleMenuBasic;
import com.jichangxiu.server.platform.entity.po.*;
import com.jichangxiu.server.platform.entity.vo.PlatformRoleAddVo;
import com.jichangxiu.server.platform.entity.vo.PlatformRoleAuthEditVo;
import com.jichangxiu.server.platform.entity.vo.PlatformRoleEditVo;
import com.jichangxiu.server.platform.entity.vo.PlatformRoleQueryVo;
import com.jichangxiu.server.platform.mapper.PlatformRoleMapper;
import com.jichangxiu.server.platform.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;

/**
 * PlatformRoleServiceImpl:
 *
 * @author Jcx
 * @create 2023-03-08 21:18
 */
@Service
public class PlatformRoleServiceImpl extends BaseServiceImpl<PlatformRoleMapper, PlatformRole> implements PlatformRoleService {

    @Resource
    private TokenUtils tokenUtils;

    @Resource
    private StrUtils strUtils;

    @Autowired
    private PlatformRoleMapper platformRoleMapper;

    @Resource
    private PlatformMenuService platformMenuService;

    @Resource
    private PlatformUserRoleService platformUserRoleService;

    @Resource
    private PlatformRoleMenuService platformRoleMenuService;

    @Resource
    private PlatformDeptRoleService platformDeptRoleService;

    /**
     * 新增角色
     *
     * @param platformRoleAddVo 角色视图对象
     * @return 是否成功
     */
    @Override
    public Boolean add(PlatformRoleAddVo platformRoleAddVo) {
        if (ObjectUtil.isEmpty(platformRoleAddVo)) {
            throw ServiceException.build("角色对象无效");
        }
        PlatformRole platformRole = PlatformRoleBasic.INSTANCE.toPlatformRole(platformRoleAddVo);
        if (ObjectUtil.isEmpty(platformRole)) {
            throw ServiceException.build("角色对象无效");
        }

        if (Constant.PLATFORM_SUPER_ROLE.equals(platformRole.getRoleCode())) {
            throw ServiceException.build("角色标识不能为 PLATFORM_SUPER_ROLE");
        }

        if (Constant.SYSTEM_SUPER_ROLE.equals(platformRole.getRoleCode())) {
            throw ServiceException.build("角色标识不能为 SYSTEM_SUPER_ROLE");
        }

        // Code 必须唯一
        PlatformRole dbPlatformRoleByCode = getOne(new LambdaQueryWrapper<PlatformRole>().eq(PlatformRole::getRoleCode, platformRole.getRoleCode()));
        if (ObjectUtil.isNotEmpty(dbPlatformRoleByCode)) {
            throw ServiceException.build(platformRole.getRoleName() + "该角色的标识重复");
        }
        // name 必须唯一
        PlatformRole dbPlatformRoleByName = getOne(new LambdaQueryWrapper<PlatformRole>().eq(PlatformRole::getRoleName, platformRole.getRoleName()));
        if (ObjectUtil.isNotEmpty(dbPlatformRoleByName)) {
            throw ServiceException.build(platformRole.getRoleName() + "该角色的名称重复");
        }

        platformRole.setRoleNo(strUtils.createNo("role"));
        platformRole.setTenantId(tokenUtils.getTenantId());

        return save(platformRole);
    }

    /**
     * 多选级联删除角色
     *
     * @param roleIdList 角色ID列表
     * @return 是否成功
     */
    @Override
    public Boolean del(List<String> roleIdList) {
        if (ObjectUtil.isEmpty(roleIdList)) {
            throw ServiceException.build("数据库中不存在需要删除的记录");
        }
        List<PlatformRole> platformRoleList = list(new LambdaQueryWrapper<PlatformRole>().in(PlatformRole::getRoleId, roleIdList));
        if (ObjectUtil.isEmpty(platformRoleList)) {
            throw ServiceException.build("数据库中不存在需要删除的记录");
        }

        platformRoleList.forEach(platformRole -> {
            if (Constant.PLATFORM_SUPER_ROLE.equals(platformRole.getRoleCode())) {
                throw ServiceException.build("标识为 PLATFORM_SUPER_ROLE 的角色不能删除");
            }

            if (Constant.SYSTEM_SUPER_ROLE.equals(platformRole.getRoleCode())) {
                throw ServiceException.build("标识为 SYSTEM_SUPER_ROLE 的角色不能删除");
            }
        });

        // 角色如果有关联用户，不能删除
        List<PlatformUserRole> platformUserRoleList = platformUserRoleService.list(new LambdaQueryWrapper<PlatformUserRole>().in(PlatformUserRole::getRoleId, roleIdList));
        if (ObjectUtil.isNotEmpty(platformUserRoleList)) {
            platformRoleList.forEach(platformRole -> {
                List<PlatformUserRole> platformUserRoles = new ArrayList<>();
                platformUserRoleList.forEach(platformUserRole -> {
                    if (platformRole.getRoleId().equals(platformUserRole.getRoleId())) {
                        platformUserRoles.add(platformUserRole);
                    }
                });
                platformRole.setPlatformUserRoles(platformUserRoles);
            });
        }

        // 角色如果有关联部门，不能删除
        List<PlatformDeptRole> platformDeptRoleList = platformDeptRoleService.list(new LambdaQueryWrapper<PlatformDeptRole>().in(PlatformDeptRole::getRoleId, roleIdList));
        if (ObjectUtil.isNotEmpty(platformDeptRoleList)) {
            platformRoleList.forEach(platformRole -> {
                List<PlatformDeptRole> platformDeptRoles = new ArrayList<>();
                platformDeptRoleList.forEach(platformDeptRole -> {
                    if (platformRole.getRoleId().equals(platformDeptRole.getRoleId())) {
                        platformDeptRoles.add(platformDeptRole);
                    }
                });
                platformRole.setPlatformDeptRoles(platformDeptRoles);
            });
        }

        platformRoleList.forEach(platformRole -> {
            List<PlatformUserRole> platformUserRoles = platformRole.getPlatformUserRoles();
            if (ObjectUtil.isNotEmpty(platformUserRoles)) {
                throw ServiceException.build(platformRole.getRoleName() + "该角色下还存在用户，不能删除");
            }
            List<PlatformDeptRole> platformDeptRoles = platformRole.getPlatformDeptRoles();
            if (ObjectUtil.isNotEmpty(platformDeptRoles)) {
                throw ServiceException.build(platformRole.getRoleName() + "该角色已被部门关联，不能删除");
            }
        });

        boolean b1 = removeBatchByIds(roleIdList);
        boolean b2 = true;
        List<PlatformRoleMenu> platformRoleMenuList = platformRoleMenuService.list(new LambdaQueryWrapper<PlatformRoleMenu>().in(PlatformRoleMenu::getRoleId, roleIdList));
        if (ObjectUtil.isNotEmpty(platformRoleMenuList)) {
            List<String> ids = new ArrayList<>();
            platformRoleMenuList.forEach(platformRoleMenu -> ids.add(platformRoleMenu.getId()));
            if (ObjectUtil.isNotEmpty(ids)) {
                b2 = platformRoleMenuService.removeBatchByIds(ids);
            }
        }
        return b1 && b2;
    }

    /**
     * 修改角色信息
     *
     * @param platformRoleEditVo 角色视图对象
     * @return 是否成功
     */
    @Override
    public Boolean edit(PlatformRoleEditVo platformRoleEditVo) {
        if (ObjectUtil.isEmpty(platformRoleEditVo)) {
            throw ServiceException.build("角色对象无效");
        }
        PlatformRole platformRole = PlatformRoleBasic.INSTANCE.toPlatformRole(platformRoleEditVo);
        if (ObjectUtil.isEmpty(platformRole)) {
            throw ServiceException.build("部门对象无效");
        }

        PlatformRole dbPlatformRole = getOne(new LambdaQueryWrapper<PlatformRole>().eq(PlatformRole::getRoleId, platformRole.getRoleId()));
        if (ObjectUtil.isEmpty(dbPlatformRole)) {
            throw ServiceException.build(platformRole.getRoleName() + "该角色在数据库中不存在");
        }

        if (Constant.PLATFORM_SUPER_ROLE.equals(dbPlatformRole.getRoleCode()) && !dbPlatformRole.getRoleCode().equals(platformRole.getRoleCode())) {
            throw ServiceException.build("标识为 PLATFORM_SUPER_ROLE 的角色标识不能修改");
        }

        if (Constant.PLATFORM_SUPER_ROLE.equals(dbPlatformRole.getRoleCode()) && !dbPlatformRole.getStatus().equals(platformRole.getStatus())) {
            throw ServiceException.build("标识为 PLATFORM_SUPER_ROLE 的角色状态不能修改");
        }

        if (Constant.SYSTEM_SUPER_ROLE.equals(dbPlatformRole.getRoleCode()) && !dbPlatformRole.getRoleCode().equals(platformRole.getRoleCode())) {
            throw ServiceException.build("标识为 PLATFORM_SUPER_ROLE 的角色标识不能修改");
        }

        if (Constant.SYSTEM_SUPER_ROLE.equals(dbPlatformRole.getRoleCode()) && !dbPlatformRole.getStatus().equals(platformRole.getStatus())) {
            throw ServiceException.build("标识为 SYSTEM_SUPER_ROLE 的角色状态不能修改");
        }

        // Code 必须唯一
        if (!platformRole.getRoleCode().equals(dbPlatformRole.getRoleCode())) {
            PlatformRole dbPlatformRoleByCode = getOne(new LambdaQueryWrapper<PlatformRole>().eq(PlatformRole::getRoleCode, platformRole.getRoleCode()));
            if (ObjectUtil.isNotEmpty(dbPlatformRoleByCode)) {
                throw ServiceException.build(platformRole.getRoleName() + "该角色的标识重复");
            }
        }

        // name 必须唯一
        if (!platformRole.getRoleName().equals(dbPlatformRole.getRoleName())) {
            PlatformRole dbPlatformRoleByName = getOne(new LambdaQueryWrapper<PlatformRole>().eq(PlatformRole::getRoleName, platformRole.getRoleName()));
            if (ObjectUtil.isNotEmpty(dbPlatformRoleByName)) {
                throw ServiceException.build(platformRole.getRoleName() + "该角色的名称重复");
            }
        }

        BeanUtil.copyProperties(platformRole, dbPlatformRole, true);
        return updateById(dbPlatformRole);
    }

    /**
     * 更新角色菜单和数据权限
     *
     * @param platformRoleAuthEditVo 角色权限视图对象
     * @return 是否成功
     */
    @Override
    public Boolean updateRoleMenuAndDataAuth(PlatformRoleAuthEditVo platformRoleAuthEditVo) {
        if (ObjectUtil.isEmpty(platformRoleAuthEditVo)) {
            throw ServiceException.build("角色对象无效");
        }
        PlatformRole dbPlatformRole = getOne(new LambdaQueryWrapper<PlatformRole>().eq(PlatformRole::getRoleId, platformRoleAuthEditVo.getRoleId()));
        if (ObjectUtil.isEmpty(dbPlatformRole)) {
            throw ServiceException.build(platformRoleAuthEditVo.getRoleId() + "该角色在数据库中不存在");
        }
        boolean b1 = true;
        if (!dbPlatformRole.getDataScope().equals(platformRoleAuthEditVo.getDataScope())) {
            dbPlatformRole.setDataScope(platformRoleAuthEditVo.getDataScope());
            b1 = updateById(dbPlatformRole);
        }

        boolean b2 = true;
        boolean b3 = true;
        // 处理菜单
        List<String> menuIds = platformRoleAuthEditVo.getMenuIds();
        // 查询数据库中已有的
        List<PlatformRoleMenu> platformRoleMenuList = platformRoleMenuService.list(new LambdaQueryWrapper<PlatformRoleMenu>().in(PlatformRoleMenu::getRoleId, platformRoleAuthEditVo.getRoleId()));

        // 最终会向数据库中添加的
        List<PlatformRoleMenu> addMenus = new ArrayList<>();
        // 会从数据库中删除的
        List<String> deleteRoleMenuIds = new ArrayList<>();

        // 如果两个对象都是空的
        if (ObjectUtil.isEmpty(menuIds) && ObjectUtil.isEmpty(platformRoleMenuList)) {
            // 这种情况啥也不做
        }
        // 如果两个对象都不是空的
        else if (ObjectUtil.isNotEmpty(menuIds) && ObjectUtil.isNotEmpty(platformRoleMenuList)) {
            // 这种情况最为复杂
            // 先处理向数据库中添加的
            for (String menuId : menuIds) {
                // 默认在数据库中不存在
                boolean flag = false;
                for (PlatformRoleMenu platformRoleMenu : platformRoleMenuList) {
                    // 如果相等说明在数据库中存在
                    if (menuId.equals(platformRoleMenu.getMenuId())) {
                        flag = true;
                        break;
                    }
                }
                // 不存在的话就新增
                if (!flag) {
                    addMenus.add(PlatformRoleMenu.builder().roleId(platformRoleAuthEditVo.getRoleId()).menuId(menuId).tenantId(tokenUtils.getTenantId()).build());
                }
            }
            // 在处理从数据库中删除的
            for (PlatformRoleMenu platformRoleMenu : platformRoleMenuList) {
                // 默认此条数据库记录不在本次页面对象中
                boolean flag = false;
                for (String menuId : menuIds) {
                    // 如果相等说明数据库记录在本次页面对象中
                    if (platformRoleMenu.getMenuId().equals(menuId)) {
                        flag = true;
                        break;
                    }
                }
                // 如果全部循环完成后发现数据库记录没有出现在本次页面提交的数据中，那么说明它已被用户删除
                if (!flag) {
                    deleteRoleMenuIds.add(platformRoleMenu.getId());
                }
            }
        }
        // 如果一个对象空的，另一个不是空的
        else if (ObjectUtil.isEmpty(menuIds) && ObjectUtil.isNotEmpty(platformRoleMenuList)) {
            // 页面传过来的对象是空的，说明需要把数据库里的数据清空，现在把数据库对象全部加入删除的列表
            platformRoleMenuList.forEach(platformRoleMenu -> deleteRoleMenuIds.add(platformRoleMenu.getId()));
        }
        // 如果一个对象空的，另一个不是空的
        else if (ObjectUtil.isNotEmpty(menuIds) && ObjectUtil.isEmpty(platformRoleMenuList)) {
            // 页面传过来的对象是不是空的，而数据库里面的对象是空的，则说明 页面上的所有数据都是新增的，需要把数据全部加入待新增的列表
            menuIds.forEach(menuId -> {
                addMenus.add(PlatformRoleMenu.builder().roleId(platformRoleAuthEditVo.getRoleId()).menuId(menuId).tenantId(tokenUtils.getTenantId()).build());
            });
        }
        if (ObjectUtil.isNotEmpty(addMenus)) {
            b2 = platformRoleMenuService.saveBatch(addMenus);
        }
        if (ObjectUtil.isNotEmpty(deleteRoleMenuIds)) {
            b3 = platformRoleMenuService.removeBatchByIds(deleteRoleMenuIds);
        }

        boolean b4 = true;
        boolean b5 = true;

        // 只有当用户的数据权限为自定义自定数据权限时才进来执行逻辑
        List<String> deptIds = platformRoleAuthEditVo.getDeptIds();
        // 查询数据库中已有的
        List<PlatformDeptRole> platformDeptRoleList = platformDeptRoleService.list(new LambdaQueryWrapper<PlatformDeptRole>().in(PlatformDeptRole::getRoleId, platformRoleAuthEditVo.getRoleId()));

        // 最终会向数据库中添加的
        List<PlatformDeptRole> addDepts = new ArrayList<>();
        // 会从数据库中删除的
        List<String> deleteRoleDeptIds = new ArrayList<>();

        // 如果两个对象都是空的
        if (ObjectUtil.isEmpty(deptIds) && ObjectUtil.isEmpty(platformDeptRoleList)) {
            // 这种情况啥也不做
        }
        // 如果两个对象都不是空的
        else if (ObjectUtil.isNotEmpty(deptIds) && ObjectUtil.isNotEmpty(platformDeptRoleList)) {
            // 这种情况最为复杂
            // 先处理向数据库中添加的
            for (String deptId : deptIds) {
                // 默认在数据库中不存在
                boolean flag = false;
                for (PlatformDeptRole platformDeptRole : platformDeptRoleList) {
                    // 如果相等说明在数据库中存在
                    if (deptId.equals(platformDeptRole.getDeptId())) {
                        flag = true;
                        break;
                    }
                }
                // 不存在的话就新增
                if (!flag) {
                    addDepts.add(PlatformDeptRole.builder().roleId(platformRoleAuthEditVo.getRoleId()).deptId(deptId).tenantId(tokenUtils.getTenantId()).build());
                }
            }
            // 在处理从数据库中删除的
            for (PlatformDeptRole platformDeptRole : platformDeptRoleList) {
                // 默认此条数据库记录不在本次页面对象中
                boolean flag = false;
                for (String deptId : deptIds) {
                    // 如果相等说明数据库记录在本次页面对象中
                    if (platformDeptRole.getDeptId().equals(deptId)) {
                        flag = true;
                        break;
                    }
                }
                // 如果全部循环完成后发现数据库记录没有出现在本次页面提交的数据中，那么说明它已被用户删除
                if (!flag) {
                    deleteRoleDeptIds.add(platformDeptRole.getId());
                }
            }
        }
        // 如果一个对象空的，另一个不是空的
        else if (ObjectUtil.isEmpty(deptIds) && ObjectUtil.isNotEmpty(platformDeptRoleList)) {
            // 页面传过来的对象是空的，说明需要把数据库里的数据清空，现在把数据库对象全部加入删除的列表
            platformDeptRoleList.forEach(platformDeptRole -> deleteRoleDeptIds.add(platformDeptRole.getId()));
        }
        // 如果一个对象空的，另一个不是空的
        else if (ObjectUtil.isNotEmpty(deptIds) && ObjectUtil.isEmpty(platformDeptRoleList)) {
            // 页面传过来的对象是不是空的，而数据库里面的对象是空的，则说明 页面上的所有数据都是新增的，需要把数据全部加入待新增的列表
            deptIds.forEach(deptId -> {
                addDepts.add(PlatformDeptRole.builder().roleId(platformRoleAuthEditVo.getRoleId()).deptId(deptId).tenantId(tokenUtils.getTenantId()).build());
            });
        }
        if (ObjectUtil.isNotEmpty(addDepts)) {
            b4 = platformDeptRoleService.saveBatch(addDepts);
        }
        if (ObjectUtil.isNotEmpty(deleteRoleDeptIds)) {
            b5 = platformDeptRoleService.removeBatchByIds(deleteRoleDeptIds);
        }

        return b1 && b2 && b3 && b4 && b5;
    }

    /**
     * 根据ID获取角色详情
     *
     * @param roleId 角色ID
     * @return 角色详情
     */
    @Override
    public PlatformRoleQueryDto info(@NotBlank(message = "角色ID不能为空") String roleId) {
        PlatformRole platformRole = getOne(new LambdaQueryWrapper<PlatformRole>().eq(PlatformRole::getRoleId, roleId));
        if (ObjectUtil.isEmpty(platformRole)) {
            throw ServiceException.build("查询不到ID为" + roleId + "的角色");
        }
        PlatformRoleQueryDto platformRoleQueryDto = PlatformRoleBasic.INSTANCE.toPlatformRoleQueryDto(platformRole);

        PlatformMenu dashboard = platformMenuService.getOne(new LambdaQueryWrapper<PlatformMenu>().eq(PlatformMenu::getName, "dashboard"));
        if (ObjectUtil.isEmpty(dashboard)) {
            throw ServiceException.build("数据库控制台菜单不存在，数据有误，请联系开发者");
        }

        List<PlatformRoleMenu> platformRoleMenuList = platformRoleMenuService.list(new LambdaQueryWrapper<PlatformRoleMenu>().in(PlatformRoleMenu::getRoleId, platformRole.getRoleId()));
        if (ObjectUtil.isEmpty(platformRoleMenuList)) {
            platformRoleMenuList = new ArrayList<>();
        }

        boolean exists = platformRoleMenuList.stream().anyMatch(platformRoleMenu -> platformRoleMenu.getMenuId().equals(dashboard.getMenuId()));

        if (!exists) {
            // dashboard 控制台是默认存在的
            platformRoleMenuList.add(PlatformRoleMenu.builder().id(IdWorker.get32UUID()).roleId(platformRole.getRoleId()).menuId(dashboard.getMenuId()).tenantId(platformRole.getTenantId()).build());
        }

        platformRole.setPlatformRoleMenus(platformRoleMenuList);
        List<PlatformDeptRole> platformDeptRoleList = platformDeptRoleService.list(new LambdaQueryWrapper<PlatformDeptRole>().in(PlatformDeptRole::getRoleId, platformRole.getRoleId()));
        if (ObjectUtil.isEmpty(platformDeptRoleList)) {
            platformDeptRoleList = new ArrayList<>();
        }
        platformRole.setPlatformDeptRoles(platformDeptRoleList);

        platformRoleQueryDto.setPlatformRoleMenuQueryDtos(PlatformRoleMenuBasic.INSTANCE.toPlatformRoleMenuQueryDtoList(platformRole.getPlatformRoleMenus()));
        platformRoleQueryDto.setPlatformDeptRoleQueryDtos(PlatformDeptRoleBasic.INSTANCE.toPlatformDeptRoleQueryDtoList(platformRole.getPlatformDeptRoles()));
        platformRoleQueryDto.setDashboardMenuId(dashboard.getMenuId());
        return platformRoleQueryDto;
    }

    /**
     * 根据租户ID和用户ID获取该用户所拥有的角色列表
     *
     * @param tenantId 租户ID
     * @param userId   用户ID
     * @return 角色列表
     */
    @Override
    public List<PlatformRoleQueryDto> getRoleListByUser(@NotBlank(message = "租户ID不能为空") String tenantId, @NotBlank(message = "用户ID不能为空") String userId) {
        return PlatformRoleBasic.INSTANCE.toPlatformRoleQueryDtoList(platformRoleMapper.getRoleListByUser(tenantId, userId));
    }

    /**
     * 分页查询角色列表
     *
     * @param platformRoleQueryVo 角色视图对象
     * @return 分页角色列表
     */
    @Override
    @DataScope
    public PageData<PlatformRoleQueryDto> pageList(PlatformRoleQueryVo platformRoleQueryVo) {
        Page<PlatformRole> page = startPage();
        List<PlatformRole> platformRoleList = platformRoleMapper.pageList(PlatformRoleBasic.INSTANCE.toPlatformRole(platformRoleQueryVo), page);
        return PageData.build(new Page<>(page.getCurrent(), page.getSize(), page.getTotal()), PlatformRoleBasic.INSTANCE.toPlatformRoleQueryDtoList(platformRoleList));
    }

}
